#include "STC89C5xRC.H"
#include "stdio.h"
#include "sys.h"
#include "uart.h"

/*Define UART parity mode*/
#define NONE_PARITY 0  // None parity
#define ODD_PARITY 1   // Odd parity
#define EVEN_PARITY 2  // Even parity
#define MARK_PARITY 3  // Mark parity
#define SPACE_PARITY 4 // Space parity

#define PARITYBIT NONE_PARITY // Testing even parity

sbit bit9 = P2 ^ 2; // P2.2 show UART data bit9
static volatile bit busy;

/**
 * @brief uart_init
 *
 * @param tim_t
 * @param baud
 * @param parity
 */
void uart_init(uart_tim_enum tim_t, uint16_t baud, uart_parity_enum parity)
{
    switch (parity)
    {
    case NONE_PARITY:
        SCON = 0x50; // 8-bit variable UART
        break;
    case SPACE_PARITY:
        SCON = 0xd2; // 9-bit variable UART, parity bit initial to 0
        break;
    default:
        SCON = 0xda; // 9-bit variable UART, parity bit initial to 1
        break;
    }

    switch (tim_t)
    {
    case UART_TIM_1:
        TMOD = 0x20 | TMOD;                   // Set Timer1 as 8-bit auto reload mode
        TH1 = TL1 = -(FOSC / 12 / 32 / baud); // Set auto-reload vaule
        TR1 = 1;                              // Timer1 start run
        break;
    case UART_TIM_2:
        TL2 = RCAP2L = (65536 - (FOSC / 32 / baud)); // Set auto-reload vaule
        TH2 = RCAP2H = (65536 - (FOSC / 32 / baud)) >> 8;
        T2CON = 0x34; // Timer2 start run
        break;
    default:
        break;
    }
    ES = 1; // Enable UART interrupt
    EA = 1; // Open master interrupt switch

    printf("uart init successfully.\r\n");
}

/**
 * @brief Uart_Isr
 *
 */
void Uart_Isr() interrupt 4
{
    if (RI)
    {
        RI = 0;     // Clear receive interrupt flag
        P0 = SBUF;  // P0 show UART data
        bit9 = RB8; // P2.2 show parity bit
    }
    if (TI)
    {
        TI = 0;   // Clear transmit interrupt flag
        busy = 0; // Clear transmit busy flag
    }
}

/**
 * @brief putchar
 *
 * @param dat
 * @return char
 */
char putchar(char dat)
{
    while (busy)
        ;      // Wait for the completion of the previous data is sent
    ACC = dat; // Calculate the even parity bit P (PSW.0)
    if (P)     // Set the parity bit according to P
    {
#if (PARITYBIT == ODD_PARITY)
        TB8 = 0; // Set parity bit to 0
#elif (PARITYBIT == EVEN_PARITY)
        TB8 = 1; // Set parity bit to 1
#endif
    }
    else
    {
#if (PARITYBIT == ODD_PARITY)
        TB8 = 1; // Set parity bit to 1
#elif (PARITYBIT == EVEN_PARITY)
        TB8 = 0; // Set parity bit to 0
#endif
    }
    busy = 1;
    SBUF = ACC; // Send data to UART buffer

    return SYS_OK;
}
